#include "osal_log.h"
#include "ossl_user.h"

#define TIME_YEAR_START 1900
#define SEM_FLAG 0666
#define GET_FLOCk_TRY_NUM 5
#define GET_FLOCk_TRY_DELAY 200000

enum select_dev_type_e {
    SELECT_HINIC_DEV = 1,
    SELECT_SSSNIC_DEV,
    SELECT_UNKNOWN_DEV,
};

static u32 g_select_dev_tag = SELECT_UNKNOWN_DEV;

/* *
 * string_cmp - string compare
 * @cmd: the string 1
 * @argc: the string 2
*  */
bool string_cmp(const char *cmd, const char *argc)
{
    int i = 0;

    if ((!cmd || !argc) || (strlen(cmd) != strlen(argc))) {
        return UDA_FALSE;
    }

    do {
        if (cmd[i] != argc[i]) {
            return UDA_FALSE;
        }
        i++;
    } while (cmd[i] != '\0');

    return UDA_TRUE;
}

/* ****************************************************************************
 函 数 名  : uda_realpath
 功能描述  :  文件路径转换(只支持绝对路径)
 输入参数  :char* file_dir
输出参数  : char* format_dir
 返 回 值  :s32

  1.日    期   : 2017年5月14日
    修改内容   : 新生成函数
**************************************************************************** */
s32 uda_realpath(const char *file_dir, size_t len, char *format_dir, size_t size)
{
    errno_t err;
    u8 file_path[PATH_MAX] = {0};

    if (NULL == file_dir || NULL == format_dir) {
        return -UDA_EINVAL;
    }

    if (realpath(file_dir, file_path) == NULL) {
        return -UDA_FAIL;
    }

    err = memcpy_s(format_dir, size, file_path, strlen(file_path));
    if (err != EOK) {
        CLI_ERR("memcpy_s execution failed!(err: %d)\n", err);
        return -UDA_FAIL;
    }

    return UDA_SUCCESS;
}
/* ****************************************************************************
 函 数 名  : uda_flock
 功能描述  : 为文件添加锁定，防止多用户同时访问一个文件
 输入参数  : const char *lock_file 文件名
             u32         operation 锁互斥时是否等待

 输出参数  : long        *fd        文件句柄
 返 回 值  : UDA_SUCCESS  加锁成功
             其他         加锁失败
  1.日    期   : 2017年05月14日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status uda_flock(const char *lock_file, u32 len, u32 operation, long *fd)
{
    u32 f_opt = 0;
    s32 fd_t = 0;
    s32 ret = 0;
    u8 try_num;
    u8 file_path[PATH_MAX] = {0};

    if ((NULL == fd) || (NULL == lock_file)) {
        return -UDA_EINVAL;
    }
    if ((realpath(lock_file, file_path) == NULL) && (errno != ENOENT)) {
        uda_printf("realpath: file path error(err: %d file_path: %s)!\n", errno, lock_file);
        return -UDA_ECMD;
    }
    fd_t = open(file_path, O_WRONLY | O_CREAT, S_IRWXU);
    if (fd_t < 0) {
        return -UDA_ECMD;
    }
    *fd = (long)fd_t;

    if (UDA_FLOCK_NOBLOCK == operation) {
        f_opt = LOCK_EX | LOCK_NB;
    } else {
        f_opt = LOCK_EX;
    }

    for (try_num = 0; try_num < GET_FLOCk_TRY_NUM; try_num++) {
        ret = flock(fd_t, (int)f_opt);
        if (ret == 0) {
            break;
        }
        usleep(GET_FLOCk_TRY_DELAY);
    }
    if (ret) {
        uda_printf("Can not get file lock (%d).\n", ret);
        goto out;
    }

    return 0;

out:
    close(fd_t);
    return ret;
}

/* ****************************************************************************
 函 数 名  : open_lockf_file
 功能描述  : 打开要添加fockf锁的文件；
 输入参数  : const char *lock_file 文件名
            u32         len       文件名长度
            long       *fd        保存的文件描述符指针

 输出参数  : 无
 返 回 值  : UDA_SUCCESS  加锁成功
            其他         加锁失败
  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status open_lockf_file(const char *lock_file, u32 len, long *fd)
{
    s32 fd_t = -1;
    u8 file_path[PATH_MAX] = {0};

    if ((lock_file == NULL) || (len == 0)) {
        return -UDA_EINVAL;
    }
    if ((realpath(lock_file, file_path) == NULL) && (errno != ENOENT)) {
        uda_printf("realpath: file path error(err: %d file_path: %s)!\n", errno, lock_file);
        return -UDA_ECMD;
    }
    fd_t = open(file_path, O_WRONLY | O_CREAT, S_IRWXO);
    if (fd_t < 0) {
        uda_printf("Lockf: can not open file fd(%d).\n", fd_t);
        return -UDA_ECMD;
    }
    *fd = (long)fd_t;

    return UDA_SUCCESS;
}

/* ****************************************************************************
 函 数 名  : uda_lockf
 功能描述  : 给文件加上fockf锁，用于标记是否有用户在使用文件；
 输入参数  : u32         operation 加锁模式: 0-非加阻塞锁，1-加阻塞锁；
            const long fd        文件句柄

 输出参数  : 无
 返 回 值  : UDA_SUCCESS  加锁成功
            其他          加锁失败
 修改历史      :
  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status uda_lockf(u32 operation, const long fd)
{
    u32 f_opt;
    s32 fd_t = -1;
    s32 ret;

    if (fd < 0) {
        return -UDA_EINVAL;
    }

    fd_t = (s32)((u32)fd & U32_MASK);
    if (operation == UDA_FLOCK_NOBLOCK) {
        f_opt = F_TLOCK;
    } else {
        f_opt = F_LOCK;
    }

    ret = lockf(fd_t, (int)f_opt, LOCKF_LOCK_ENTIRE_FILE);
    if (ret) {
        return ret;
    }

    return UDA_SUCCESS;
}

/* ****************************************************************************
 函 数 名  : get_lockf_status
 功能描述  : 获取文件锁状态
 输入参数  : const long fd 文件句柄

 输出参数  : 无
 返 回 值  : 0            文件未上锁
            -1           文件已上锁
            其他          获取锁失败
  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status get_lockf_status(const long fd)
{
    s32 fd_t = -1;
    s32 ret;

    if (fd < 0) {
        return -UDA_EINVAL;
    }

    fd_t = (s32)((u32)fd & U32_MASK);
    ret = lockf(fd_t, F_TEST, LOCKF_LOCK_ENTIRE_FILE);

    return ret;
}

/* ****************************************************************************
 函 数 名  : uda_unlockf
 功能描述  : 释放文件的锁定，并关闭文件；
 输入参数  : const long fd 文件句柄

 输出参数  : 无
 返 回 值  : UDA_SUCCESS  解锁成功
            其他          解锁失败
  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status uda_unlockf(const long fd)
{
    s32 fd_t = -1;
    s32 ret;

    if (fd < 0) {
        return -UDA_EINVAL;
    }

    fd_t = (s32)((u32)fd & U32_MASK);
    ret = lockf(fd_t, F_ULOCK, LOCKF_LOCK_ENTIRE_FILE);
    if (ret) {
        uda_printf("Lockf: can not release file fd[%d] lock.\n", fd_t);
        return ret;
    }

    ret = close(fd_t);
    if (ret) {
        uda_printf("Lockf: can not close file fd[%d].\n", fd_t);
        return ret;
    }

    return 0;
}

/* ****************************************************************************
 函 数 名  : close_lockf_file
 功能描述  : 关闭文件；
 输入参数  : const long fd 文件句柄

 输出参数  : 无
 返 回 值  : UDA_SUCCESS  解锁成功
            其他          解锁失败
  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
static uda_status close_lockf_file(const long fd)
{
    s32 fd_t = -1;
    s32 ret = 0;

    if (fd < 0) {
        return -UDA_EINVAL;
    }

    fd_t = (s32)((u32)fd & U32_MASK);
    ret = close(fd_t);
    if (ret) {
        uda_printf("Lockf: can not close file fd[%d].\n", fd_t);
        return ret;
    }

    return 0;
}

/* ****************************************************************************
 函 数 名  : uda_unflock
 功能描述  : 释放文件的锁定
 输入参数  : long *fd
 输出参数  : 无
 返 回 值  : 无

  1.日    期   : 2017年5月14日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status uda_unflock(const long *fd)
{
    s32 fd_t;
    s32 ret = 0;

    if (NULL == fd) {
        return -UDA_EINVAL;
    }

    if (*fd < 0) {
        return -UDA_EINVAL;
    }

    fd_t = (s32)((u32)(*fd) & U32_MASK);
    ret = flock(fd_t, LOCK_UN);
    if (ret) {
        uda_printf("Can not release file [%d] lock.\n", fd_t);
        goto out;
    }

    ret = close(fd_t);
    if (ret) {
        uda_printf("Can not close file [%d].\n", fd_t);
        return ret;
    }

    return 0;

out:
    close(fd_t);
    return ret;
}

/* ****************************************************************************
 函 数 名  : create_file
 功能描述  : 根据输入的设备名称，选择驱动设备的路径
 输入参数  : char *name
            u32 len
 输出参数  : 无
 返 回 值  : UDA_SUCCESS  选择成功
            其他          选择失败
  1.日    期   : 2022年5月13日
    修改内容   : 新生成函数
**************************************************************************** */
void select_dev_path(char *name)
{
    if (!strncmp(name, CMP_SSSNIC_DEV_NAME, strlen(CMP_SSSNIC_DEV_NAME))) {
        g_select_dev_tag = SELECT_SSSNIC_DEV;
    /*
     * 当前支持snic*设备名称的识别，hinic*设备名称，保留为兼容模式；
     * } else if (!strncmp(name, CMP_HINIC_DEV_NAME, strlen(CMP_HINIC_DEV_NAME))) {
     *     g_select_dev_tag = SELECT_HINIC_DEV;
     */
    } else {
        g_select_dev_tag = SELECT_UNKNOWN_DEV;
    }
}

/* ****************************************************************************
 函 数 名  : create_file
 功能描述  : 打开设备
 输入参数  : u32 adapter_index
 输出参数  : 无
 返 回 值  : 文件句柄

  1.日    期   : 2017年5月13日
    修改内容   : 新生成函数
**************************************************************************** */
s32 create_file(void)
{
    s32 fd;

    switch (g_select_dev_tag) {
        case SELECT_HINIC_DEV:
            fd = open(HINIC3_DEV_PATH, O_RDWR);
            if (fd < 0) {
                printf("Fail to open: %s\n", HINIC3_DEV_PATH);
                return -UDA_ENXIO;
            }
            return fd;
        case SELECT_SSSNIC_DEV:
            fd = open(SSSNIC_DEV_PATH, O_RDWR);
            if (fd < 0) {
                printf("Fail to open: %s\n", SSSNIC_DEV_PATH);
                return -UDA_ENXIO;
            }
            return fd;
        case SELECT_UNKNOWN_DEV:
            fd = open(HINIC3_DEV_PATH, O_RDWR); /* 未选择设备，打开hinic驱动失败时，尝试打开另一个驱动 */
            if (fd < 0) {
                fd = open(SSSNIC_DEV_PATH, O_RDWR);
            }
            if (fd < 0) {
                printf("Unable to open drive device!\n");
                return -UDA_ENXIO;
            }
            return fd;
        default:
            printf("Invalid selection flag, please check the code!\n");
            return -UDA_ENXIO;
    }
}
/* ****************************************************************************
 函 数 名  : close_file
 功能描述  : 关闭文件
 输入参数  : 句柄
 输出参数  : 无
 返 回 值  : 无

  1.日    期   : 2017年5月14日
    修改内容   : 新生成函数
**************************************************************************** */
void close_file(int fd)
{
    close(fd);
}
/* ****************************************************************************
 函 数 名  : io_ctl
 功能描述  : ioctl
 输入参数  : 句柄
 输出参数  : 无
 返 回 值  : 无

  1.日    期   : 2017年5月14日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status io_ctl(int fd, void *inBuf, long inBufLen, void *outBuf, long outBufLen)
{
    int ret = 0;
    u32 cmd = NICTOOL_CMD_TYPE;

    ret = ioctl(fd, _IO(NIC_TOOL_MAGIC, cmd), inBuf);

    return ret;
}
/* ****************************************************************************
 函 数 名  : uda_access
 功能描述  : 查询是否有无该文件
 输入参数  : file_dir 文件名
 输出参数  : 无
 返 回 值  : 有该文件返回成功，否则返回错误代码
  1.日    期   : 2017年5月15日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status uda_access(const char *file_dir)
{
    return (access(file_dir, F_OK) ? (-UDA_ENOOBJ) : UDA_SUCCESS);
}
/* ****************************************************************************
函 数 名  : uda_get_bus_num
功能描述  : 设备名转换成全局function_id，Linux中默认返回成功
输入参数  : char *name
           size_t len
输出参数  : u32 *func_id
返 回 值  : s32

1.日    期   : 2017年5月12日
修改内容   : 新生成函数
**************************************************************************** */
s32 uda_get_bus_num(char *name, size_t len, int *bus_num)
{
    *bus_num = LINUX_DEFAULT_ID;
    return UDA_SUCCESS;
}

/* ****************************************************************************
 函 数 名  : uda_msleep
 功能描述  : 毫秒级延时
 输入参数  : s32 milliseconds  毫秒
 输出参数  : 无
 返 回 值  : 无

  1.日    期   : 2017年7月1日
    修改内容   : 新生成函数
**************************************************************************** */
void uda_msleep(long milliseconds)
{
    struct timeval delay;
    delay.tv_sec = 0;
    /* ms to us needs to be multiplied by 1000 */
    delay.tv_usec = milliseconds * 1000;
    (void)select(0, NULL, NULL, NULL, &delay);
    return;
}

/* ****************************************************************************
 函 数 名  : uda_create_file_name
 功能描述  : 由原文件名创建含时间的文件名
 输入参数  : 原文件名和文件名长度
 输出参数  : 目标文件名
 返 回 值  : 无

  1.日    期   : 2017年8月2日
    修改内容   : 新生成函数
**************************************************************************** */
int uda_create_file_name(const u8 *src_name, u8 file_len, const u8 *area, const u8 *dev_name, u8 *dest_name)
{
    time_t timep;
    struct tm *p;
    u8 path_len;
    u8 max_time_len;
    int ret;

    /* 获取当前的UTC时间 */
    timep = time(NULL);
    p = localtime(&timep);
    if (!p)
        return -1;

    path_len = file_len - (u8)strlen(".log");

    (void)memcpy_s(dest_name, MAX_NUM_OF_PATH_ULOG, src_name, path_len);

    max_time_len = MAX_NUM_OF_PATH_ULOG - path_len;

    ret = snprintf_s(dest_name + path_len, max_time_len, max_time_len, "_%s_%s_%04d_%02d_%02d_%02d_%02d_%02d.log", area,
        dev_name, TIME_YEAR_START + p->tm_year, 1 + p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
    if (ret < 0) {
        printf("uda_create_file_name failed.\n");
        return ret;
    }
    return 0;
}
/* ****************************************************************************
 函 数 名  : uda_uncompress_gz_file
 功能描述  : 将gz文件解压
 输入参数  : 无
 输出参数  : 无
 返 回 值  : 无

  1.日    期   : 2017年8月22日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status uda_uncompress_gz_file(const u8 *dev_name)
{
    u8 file_path_gz[256] = {0};
    u8 file_path_log[256] = {0};
    u8 command[512] = {0};
    int ret;

    ret = snprintf_s(file_path_gz, sizeof(file_path_gz),
        sizeof(HINICADM_FIRMWARE_LOG_DIR_PATH) + strlen(dev_name) + strlen("_index.gz"),
        "%s%s%s", HINICADM_FIRMWARE_LOG_DIR_PATH, dev_name, "_index.gz");
    if (ret == F_FAILED) {
        printf("Snprintf file_path_gz failed.\n");
        return -UDA_FAIL;
    }

    ret = snprintf_s(file_path_log, sizeof(file_path_log),
        sizeof(HINICADM_FIRMWARE_LOG_DIR_PATH) + strlen(dev_name) + strlen("_index.log"), "%s%s%s",
        HINICADM_FIRMWARE_LOG_DIR_PATH, dev_name, "_index.log");
    if (ret == F_FAILED) {
        printf("Snprintf file_path_log failed.\n");
        return -UDA_FAIL;
    }

    ret = snprintf_s(command, sizeof(command),
        strlen("gunzip -qc ") + strlen(file_path_gz) + strlen(" > ") + strlen(file_path_log),
        "%s%s%s%s", "gunzip -qc ", file_path_gz, " >", file_path_log);
    if (ret == F_FAILED) {
        printf("Snprintf command failed.\n");
        return -UDA_FAIL;
    }

    if (0 > system(command)) {
        printf("failed to uncmpress gz file!\n");
        return -UDA_FAIL;
    } else {
        return UDA_SUCCESS;
    }
}

/* ****************************************************************************
 函 数 名  : uda_get_username_ip
 功能描述  : 获取打开本应用操作者所使用的用户名和登陆IP
 输入参数  : 无
 输出参数  : char *user 登陆用户名
             char *ip   登陆IP
 返 回 值  : 无

  1.日    期   : 2014年09月29日
    修改内容   : 新生成函数
**************************************************************************** */
void uda_get_username_ip(char *user, char *ip, u32 len)
{
    const char *user_temp = NULL;
    const char *ip_temp = NULL;
    u32 i = 0;
    int ret;

    /* get host name */
    if (NULL != (user_temp = getenv("LOGNAME"))) {
        ret = snprintf_s(user, OP_LOG_USER_NAME_SIZE, OP_LOG_USER_NAME_SIZE, "%s", user_temp);
        if (ret == F_FAILED) {
            printf("Snprintf log name failed.\n");
            return;
        }
    } else {
        ret = snprintf_s(user, OP_LOG_USER_NAME_SIZE, OP_LOG_USER_NAME_SIZE, "%s", "unknown");
        if (ret == F_FAILED) {
            printf("Snprintf log name failed.\n");
            return;
        }
    }

    /* get ip address */
    if (NULL != (ip_temp = getenv("SSH_CONNECTION"))) {
        /* break when NULL or space */
        for (i = 0; ((0 != ip_temp[i]) && (0x20 != ip_temp[i])); i++) {
            ip[i] = ip_temp[i];
        }
    } else if (NULL != (ip_temp = getenv("REMOTEHOST"))) {
        ret = snprintf_s(ip, OP_LOG_IP_STR_SIZE, OP_LOG_IP_STR_SIZE, "%s", ip_temp);
        if (ret == F_FAILED) {
            printf("Snprintf remote host name failed.\n");
            return;
        }
    } else {
        ret = snprintf_s(ip, OP_LOG_IP_STR_SIZE, OP_LOG_IP_STR_SIZE, "%s", "local");
        if (ret == F_FAILED) {
            printf("Snprintf remote host name failed.\n");
            return;
        }
    }

    return;
}

void record_syslog(const char *ident, int priority, char *logs, u32 len)
{
    if (!logs || !ident) {
        printf("Invalid parameter [%s].\n", __FUNCTION__);
        return;
    }

    openlog(ident, LOG_CONS | LOG_PID, LOG_USER);
    syslog(priority, "%s", logs);
    closelog();

    return;
}

/* ****************************************************************************
 函 数 名  : comm_sem
 功能描述  : 创建信号量和获取信号量公用函数
 输入参数  : int module_id 模块ID
            int nums      信号量个数
            int semflag   创建信号权限
 输出参数  : 无
 返 回 值  : SEM_ERROR   初始化失败
            其他值       创建返回的信号ID

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
static int comm_sem(int module_id, int nums, int semflag)
{
    /* get key */
    key_t key = ftok(HIADM3_FTOK_PATH, module_id);
    if (key == SEM_ERROR) {
        perror("Comm_sem ftok");
        return SEM_ERROR;
    }

    int semid = semget(key, nums, semflag);
    if (semid == SEM_ERROR) {
        return SEM_ERROR;
    }
    return semid;
}

/* ****************************************************************************
 函 数 名  : create_sems
 功能描述  : 创建含有nums个信号量的集合
 输入参数  : int module_id 模块ID
            int nums      信号量个数
 输出参数  : 无
 返 回 值  : SEM_ERROR   初始化失败
            其他值       创建返回的信号ID

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
int create_sems(int module_id, int nums)
{
    return comm_sem(module_id, nums, IPC_CREAT | IPC_EXCL | SEM_FLAG);
}

/* ****************************************************************************
 函 数 名  : get_sems
 功能描述  : 获取信号量ID
 输入参数  : int module_id 模块ID
 输出参数  : 无
 返 回 值  : SEM_ERROR   初始化失败
            其他值       创建返回的信号ID

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
int get_sems(int module_id)
{
    return comm_sem(module_id, 0, IPC_CREAT);
}

/* ****************************************************************************
 函 数 名  : init_sems
 功能描述  : 初始化semid对应的信号量集中编号为which的信号量值为value
 输入参数  : int sem_id 信号集ID
            int which  semid对应的信号量集中的编号
            int value  初始化信号量值为value
 输出参数  : 无
 返 回 值  : SEM_SUCCESS 初始化成功
            其他值       初始化失败

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
int init_sems(int sem_id, int which, int value)
{
    union semun _semun;
    _semun.val = value;
    int ret = semctl(sem_id, which, SETVAL, _semun);
    if (ret == SEM_ERROR) {
        perror("Init_sem");
        return ret;
    }
    return SEM_SUCCESS;
}

/* ****************************************************************************
 函 数 名  : destroy_sems
 功能描述  : 释放该信号量集
 输入参数  : int sem_id 信号集ID
 输出参数  : 无
 返 回 值  : SEM_SUCCESS 初始化成功
            其他值       初始化失败

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status destroy_sems(int sem_id)
{
    int ret = semctl(sem_id, 0, IPC_RMID, NULL);
    if (ret == SEM_ERROR) {
        perror("Rm_sem");
        return ret;
    }
    return SEM_SUCCESS;
}

/* ****************************************************************************
 函 数 名  : comm_sem_op
 功能描述  : 对信号量VP操作的公共函数
 输入参数  : int sem_id 信号集ID
            int which  semid对应的信号量集中的编号
            int op     OP操作数
            int flg    信号操作标识，非零设置为SEM_UNDO，零值设置为IPC_NOWAIT
 返 回 值  : SEM_SUCCESS 初始化成功
            SEM_ERROR   初始化失败

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
static int comm_sem_op(int sem_id, int which, int op, int flg)
{
    struct sembuf _sembuf;
    _sembuf.sem_num = (unsigned short)which;
    _sembuf.sem_op = (short)op;
    _sembuf.sem_flg = flg ? SEM_UNDO : IPC_NOWAIT; /* IPC_NOWAIT  SEM_UNDO */
    return semop(sem_id, &_sembuf, 1);
}


/* ****************************************************************************
 函 数 名  : sem_p
 功能描述  : 表示分配，信号量值-1
 输入参数  : int sem_id 信号集ID
            int which  semid对应的信号量集中的编号
            int flg    信号操作标识，非零设置为SEM_UNDO，零值设置为IPC_NOWAIT
 输出参数  : 无
 返 回 值  : SEM_SUCCESS 初始化成功
            SEM_ERROR   初始化失败

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status sem_p(int sem_id, int which, int flg)
{
    return comm_sem_op(sem_id, which, -1, flg);
}

/* ****************************************************************************
 函 数 名  : sem_v
 功能描述  : 表示释放，信号量值+1
 输入参数  : int sem_id 信号集ID
            int which  semid对应的信号量集中的编号
            int flg    信号操作标识，非零设置为SEM_UNDO，零值设置为IPC_NOWAIT
 输出参数  : 无
 返 回 值  : SEM_SUCCESS 初始化成功
            SEM_ERROR   初始化失败

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
uda_status sem_v(int sem_id, int which, int flg)
{
    return comm_sem_op(sem_id, which, 1, flg);
}

/* ****************************************************************************
 函 数 名  : comm_shm
 功能描述  : 创建和获取共享内存公用函数
 输入参数  : int module_id 模块ID
            int size      共享内存大小
            int semflag   创建信号权限
 输出参数  : 无
 返 回 值  : SHM_ERROR 创建或获取失败
            其他值     创建或获取成功，返回共享内存的标识符

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
static int comm_shm(int module_id, int size, int shmflag)
{
    /* get key */
    key_t key = ftok(HIADM3_SHARE_MEM_PATH, module_id);
    if (key == SHM_ERROR) {
        perror("Shm_ftok");
        return SHM_ERROR;
    }

    int semid = shmget(key, size, shmflag);
    if (semid == SHM_ERROR) {
        return SHM_ERROR;
    }
    return semid;
}

/* ****************************************************************************
 函 数 名  : create_shm
 功能描述  : 创建size大小的共享内存空间
 输入参数  : int module_id 模块ID
            int size      共享内存大小
 输出参数  : 无
 返 回 值  : SHM_ERROR 创建失败
            其他值     创建成功，返回共享内存的标识符

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
int create_shm(int module_id, int size)
{
    return comm_shm(module_id, size, IPC_CREAT | IPC_EXCL | SEM_FLAG);
}

/* ****************************************************************************
 函 数 名  : get_shm
 功能描述  : 获取已创建的共享内存标识符
 输入参数  : int module_id 模块ID
            int size      共享内存大小
 输出参数  : 无
 返 回 值  : SHM_ERROR 获取失败
            其他值     获取成功，返回共享内存的标识符

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
int get_shm(int module_id, int size)
{
    return comm_shm(module_id, size, IPC_CREAT);
}

/* ****************************************************************************
 函 数 名  : get_shm_addr
 功能描述  : 把共享内存区对象映射到调用进程的地址空间
 输入参数  : int  shm_id    共享内存的标识符
            void *shm_addr 指定共享内存在进程内存地址，指定为NULL则内核自动指定
            int  shmflg    SHM_RDONLY: 为只读模式，其他为读写模式
            void **dste_add 取共享内存区映射到调用进程空间的指针地址
 输出参数  : void **dste_add 返回共享内存区映射到调用进程的空间地址
 返 回 值  : SHM_ERROR    获取映射的进程空间地址失败
            SHM_SUCCESS  获取映射的进程空间地址成功

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
int get_shm_addr(int shm_id, const void *shm_addr, int shmflg, void **dste_addr)
{
    /* 调用成功时返回一个指向共享内存第一个字节的指针，如果调用失败返回-1 */
    void *addr = shmat(shm_id, shm_addr, shmflg);
    if (addr == SHM_ERROR) {
        perror("Get_shm_addr");
        return SHM_ERROR;
    }
    *dste_addr = (void *)addr;
    return SHM_SUCCESS;
}

/* ****************************************************************************
 函 数 名  : destroy_shm
 功能描述  : 删除共享内存
 输入参数  : int  shm_id    共享内存的标识符
 输出参数  : 无
 返 回 值  : SHM_ERROR    删除共享内存失败
            SHM_SUCCESS  删除共享内存成功

  1.日    期   : 2020年11月6日
    修改内容   : 新生成函数
**************************************************************************** */
int destroy_shm(int shm_id)
{
    int ret = shmctl(shm_id, IPC_RMID, NULL);
    if (ret == SHM_ERROR) {
        perror("Rm_shm");
        return ret;
    }
    return SHM_SUCCESS;
}